iT邦幫忙

2023 iThome 鐵人賽

DAY 10
0

學習 SASS 來撰寫並管理更龐大的專案

SASS 原先是 Ruby 這套程式語言,在設計樣式(CSS)時因撰寫習慣而衍生出來的語言,它具有使用「縮排語法」排版的語法結構,並提供了方便的巢狀結構,而得益於誕生之後的持續發展,直到現今他具備了變數、回圈、模組、函式等程式開發常見的概念,並一躍成了如今前端開發的主要工具之一。

縮排語法編譯之前的程式

使用巢狀結構使得我們的語法具有明確的階層性,可以更好的用 html 的思維進行開發設計。

nav
  ul
    margin: 0
    padding: 0
    list-style: none

  li
    display: inline-block

  a
    display: block
    padding: 6px 12px
    text-decoration: none

縮排語法編譯之後的程式

在編譯完之後再有階層的情況下,還會自動幫我們帶如選擇器的標籤結構

nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

nav li {
  display: inline-block;
}

nav a {
  display: block;
  padding: 6px 12px;
  text-decoration: none;
}

為什麼我們要使用 SASS?

這邊說回來我們為何要使用 SASS,這邊可以套用他官方網站介紹自己的話語:
原文:「Sass is the most mature, stable, and powerful professional grade CSS extension language in the world.」 翻譯:「Sass 是世界上最成熟、穩定、強大且專業級 CSS 擴展語言」

而擴充語法在這裡有一個很重要的概念,這裡可以簡單地說成他並未捨棄任何原有的 CSS 語法,而是以原先的 CSS 作為基底,在此基礎上新增屬於 SASS 可以使用的功能,因此即使在完全不操作 SASS 的情況下,也可以依照原先的開發習慣照常開發。

說回我們為什麼需要使用 SASS 來撰寫樣式,先不要管他對於自身的評價,我們可以去反思原先 CSS 有什麼問題,過多雷同的樣式撰寫,類似的命名規則需重複設定,專案規模大時色彩的不可控,尺寸與間距若沒預設規範尺寸時將永遠不可知等,傳統的樣式撰寫始終只是負責進行畫面的呈現,維護與可讀等很顯然不是他的考慮範圍,而在 SASS 的設計裡,這一些問題將會一次性的獲得解決,而這也是我們將要使用 SASS 的最佳誘因。

編譯之前的程式(SCSS)

.main {
  max-width: 1200px;
  width: 80%;
  margin: auto;
}

.list {
  display: flex;
}

編譯之後的程式(CSS)

.main {
  max-width: 1200px;
  width: 80%;
  margin: auto;
}

.list {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
}

這邊需要提及一個概念,為了讓 CSS 可以在各種瀏覽器正常運作,我們會需要在一些屬性或參數前新增前綴,雖然即使不加其實顯示也不一定會有問題,但保守一點總是比較好的,然而在實務上這點其實非常讓人困擾,因為這類型的樣式或屬性可說是數不勝數,一個一個撰寫更是一件暗無天日的考驗,而此時 SASS 這類型的擴充語言就像是聽見我們的哀嚎般,在後來的版本中將此納入了匯出的格式(可靠設定讓他不產出前綴),使得我們不用再自行新增這麼大量的額外標籤。

前綴說明文件

簡易的 SASS 編譯器安裝與操作

在實際專案當中,我們其實並不會推薦使用這個編譯器,原因是因為編譯版本的問題,以 SASS 目前最新版的語法來說,這個編譯器遺憾的並不支援,而在實務進入專案與架構的開發時,我們的開發環境也會自行幫我們使用最新版本進行編譯,因此並不需要採用此編譯器,但在初步探索 SASS 並學習的現在,這套依然會是我們的最佳首選。

延伸模組套件

VSCode SASS 編譯套件下載

因為實際要跑新版的編譯器,需操作電腦 node 與 npm 環境等,對大多數沒有學習過 JavaScript 或電腦指令的同學相當的不友善。

Live Sass Compiler 安裝畫面

安裝完成後的初次啟動

在我們安裝完成之後,理論上就可以直接啟動編譯,但要記住我們不是魔法師,無法無中生有的讓他編譯出東西,因此在初次的操作中,請同學在專案的任何一個地方建立一個 style.scss 的檔案,內容可以先不放置,然後在點擊下方 Watch Sass 的按鈕開始編譯。

:::warning
注意:請記得開啟一個資料夾
:::

若需要填寫內容,可以使用下方範例
.main {
  max-width: 1200px;
  width: 80%;
  margin: auto;
}

.list {
  display: flex;
}

SASS 編譯

此時不出意外的話,style.css 與 style.css.map 的檔案將會自動被建置出來,.map 的檔案是協助我們的開發者工具確認 css 與 scss 之間的結構的,並記錄操作位子的檔案,通常並不需要去在意。

細心的同學應該會發現,我們此時用的副檔名並不是使用 .sass 而是使用 .scss,這是為了因應過往 CSS 開發者的操作習慣,縮排語法並畢竟與原生的語法有著過大的落差,因此 SASS 官方提供了一套更貼近於 CSS 的語法,使我們可以在操作過往 CSS 的習慣下,繼續使用 SASS 所提供的功能。

定義變數(Variables)並嘗試使用

編譯之前的程式(SCSS)

$color_accent: #1f1b7d;
$color_text-color: #13122d;

body {
  background-color: $color_accent;
  color: $color_text-color;
}

h1 {
  color: $color_accent;
}

編譯之後的程式(CSS)

body {
  background-color: #1f1b7d;
  color: #13122d;
}

h1 {
  color: #1f1b7d;
}

開始使用巢狀(Nesting)結構撰寫樣式

在撰寫 SCSS 的使用,我們可以藉由一個關鍵字「&」,去取得目前所在選擇器的寫法,他可以很輕鬆的讓我們指定自身的偽元素或偽選擇器,並且在 BEM 語法規章的撰寫中,也讓我們可以更優雅的撰寫我們的樣式。

編譯之前的程式(SCSS)

body {
  .container {
    max-width: 1200px;
    width: 80%;
  }
}

.box {
  width: 80px;

  .box__title {
    font-size: 1.5em;
  }

  &__text {
    font-size: 1.1em;
  }
}

編譯之後的程式(CSS)

body .container {
  max-width: 1200px;
  width: 80%;
}

.box {
  width: 80px;
}

.box .box__title {
  font-size: 1.5em;
}

.box__text {
  font-size: 1.1em;
}

修改編譯器操作

  "liveSassCompile.settings.formats": [
    {
      "extensionName": ".css",
      "format": "expanded",
      "savePath": "/assets/css"
    }
  ],
參數說明
  • extensionName:設定匯出檔案副檔名
  • format:設定編譯後的檔案內容排版方式
    • compressed:壓縮的排版格式,會將全部的程式壓縮成一行「適合線上版本」
    • expanded:完全展開的排版格式,會按照合適開發者閱讀的方式排版「適合開發版本」
  • savePath:設定檔案編譯完成後的存擋位置

暸解模組(Modules)概念與片段(Partials)

如同顏色定義的檔案與一些參數設定等等,這些很明顯是不需要進入我們最終產出的結果,因此我們可以把檔案名稱前面加上「 _ 」這個下底線,編譯器再看到這個前綴時會自動不對他進行編譯。

編譯之前的程式(SCSS)

// _color.scss
$color_accent: #1f1b7d;
$color_text-color: #13122d;
// style.scss
@import 'color';

body {
  background-color: $color_accent;
  color: $color_text-color;
}

h1 {
  color: $color_accent;
}

官網的範例使用的是 @use ,但因為我們所使用的編譯器的版本問題,因此無法進行這此操作。

編譯之後的程式(CSS)

body {
  background-color: #1f1b7d;
  color: #13122d;
}

h1 {
  color: #1f1b7d;
}

應用混合(Mixins)避免類似工作重複

在撰寫樣式時,我們很常需要對「同樣」類型的 UI 進行重複的操作,而這很顯然並不符合效率這一詞,而混合(Mixin)的操作,可以協助我們進行這類型重複的撰寫,並且讓我們可以藉由自主設定變數的方式,快速製造出各類不同的樣式,並且我們甚至可以在變數後方增添預設參數,並藉由關鍵字 @include 進行操作。

編譯之前的程式(SCSS)

@mixin btnHover($backgroundColor, $hoverColor: #1e1e6f) {
  padding: 10px 20px;
  background-color: $backgroundColor;
  color: white;
  transition: background-color 300ms;

  &:hover {
    background-color: $hoverColor;
    // background-color: darken($color: $backgroundColor, $amount: 20);
  }
}

.blue-btn {
  @include btnHover(blue);
}

.red-btn {
  @include btnHover(red, rgb(114, 28, 28));
}

在上方範例的註解中,我們用了 SASS 提供的一個色彩函式,使我們可以透過計算飽和度或明亮度等方式產生色彩,這使我們在設計與操作上擁有了更加龐大的彈性。
相關文件檔案

編譯之後的程式(CSS)

.blue-btn {
  padding: 10px 20px;
  background-color: blue;
  color: white;
  -webkit-transition: background-color 300ms;
  transition: background-color 300ms;
}

.blue-btn:hover {
  background-color: #1e1e6f;
}

.red-btn {
  padding: 10px 20px;
  background-color: red;
  color: white;
  -webkit-transition: background-color 300ms;
  transition: background-color 300ms;
}

.red-btn:hover {
  background-color: #721c1c;
}
/*# sourceMappingURL=style.css.map */

使用延展或繼承(Extend/Inheritance)的概念撰寫程式

在繼承與延展的操作中,我們可以藉由 @extend 的方式,來將我們目前的區塊進行繼承的操作,概念上就是讓目前的區塊,可以去繼承其他的樣式所撰寫的內容,其中也包含了複雜的階層結構,而另外 SASS 也有提供一個 「佔用類別(placeholder classes)」,他可以允許我們先行定義一個區塊並進行撰寫,隨後在由其他的樣式進行繼承。

編譯之前的程式(SCSS)
%flex-center {
  display: flex;
  align-items: center;
  justify-content: center;
}

body {
  min-height: 100vh;

  @extend %flex-center;
}

.header {
  @extend body;
}

.navbar {
  @extend %flex-center;
}
編譯之後的程式(CSS)
body, .header, .navbar {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  -webkit-box-pack: center;
      -ms-flex-pack: center;
          justify-content: center;
}

body, .header {
  min-height: 100vh;
}

額外範例

以下方的範例為例,我們甚至連複雜的階層結構都可以進行繼承,這使得我們在相同 UI 的撰寫上,可以更加方便地進行操作。

ul {
  display: block;

  li {
    display: inline-block;
  }
}

.work {
  @extend ul;
}
ul, .work {
  display: block;
}

ul li, .work li {
  display: inline-block;
}

SCSS 進階操作

其實 SCSS 的進階操作有非常多的討論空間,但因為我們是初步進行學習,因此這邊就先只對常用的「流程控制規則(Flow Control)」進行探討。

@if and @else 布林判斷

布林的判斷其實是我們日常生活的常態,同時他也是計算機語言的根基之一,但說起來其實並不複雜,他就是單純的 Yes or No 而已。

編譯之前的程式(SCSS)
@mixin avatar($size, $circle: false) {
  width: $size;
  height: $size;

  @if $circle {
    border-radius: $size / 2;
  } @else {
    border-radius: 10px;
  }
}

.square-avatar {
  @include avatar(100px, $circle: false);
}

.circle-avatar {
  @include avatar(100px, $circle: true);
}
編譯之後的程式(CSS)
.square-avatar {
  width: 100px;
  height: 100px;
  border-radius: 10px;
}

.circle-avatar {
  width: 100px;
  height: 100px;
  border-radius: 50px;
}

@each 遍歷操作

each 的作用是會對一個實體進行遍歷,基本上就是一個不漏的全部進行一次操作,當我們對於區塊有明確的需求或定義時,他將是我們堅定的朋友。

編譯之前的程式(SCSS)
$sizes: 40px, 50px, 80px;

@each $size in $sizes {
  .icon-#{$size} {
    font-size: $size;
    height: $size;
    width: $size;
  }
}
編譯之後的程式(CSS)
.icon-40px {
  font-size: 40px;
  height: 40px;
  width: 40px;
}

.icon-50px {
  font-size: 50px;
  height: 50px;
  width: 50px;
}

.icon-80px {
  font-size: 80px;
  height: 80px;
  width: 80px;
}
額外範例
$titles: (
  'h1': 2rem,
  'h2': 1.75rem,
  'h3': 1.5rem,
);

@each $name, $size in $titles {
  #{$name} {
    color: rgb(74, 61, 104);
    font-size: $size;
  }
}
h1 {
  color: #4a3d68;
  font-size: 2rem;
}

h2 {
  color: #4a3d68;
  font-size: 1.75rem;
}

h3 {
  color: #4a3d68;
  font-size: 1.5rem;
}

@for 迴圈操作

for 迴圈是在任何程式語言中的老朋友,我們可以藉由他去跑一個累計的迴圈操作,理論上當我們遇到重複性質高的工作時,for 就會來幫我們解決這個問題。

編譯之前的程式(SCSS)
@for $i from 1 through 3 {
  .col-#{$i} {
    flex: $i;
  }
}
編譯之後的程式(CSS)
.col-1 {
  -webkit-box-flex: 1;
      -ms-flex: 1;
          flex: 1;
}

.col-2 {
  -webkit-box-flex: 2;
      -ms-flex: 2;
          flex: 2;
}

.col-3 {
  -webkit-box-flex: 3;
      -ms-flex: 3;
          flex: 3;
}

其實最後還有一個 @while 操作,但因為這會牽扯到 @function 等函式應用,因此在基礎課程先不進行談論。


上一篇
響應式網頁的基礎涵養與使用 Bootstrap 了解隔線
下一篇
如何使用 SCSS 讓我們更輕鬆的工作
系列文
給前端新手的圖文故事30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言